package com.xw.echo.core.proxy;

import com.xw.echo.core.annotation.FaultRetry;
import com.xw.echo.core.cluster.Cluster;
import com.xw.echo.core.cluster.LoadBalancer;
import com.xw.echo.core.cluster.fault.ClusterFault;
import com.xw.echo.core.cluster.fault.FallRetry;
import com.xw.echo.core.nacos.client.NacosConsumer;
import com.xw.echo.core.protocol.MethodInvokData;
import com.xw.echo.core.register.HostAndPort;
import com.xw.echo.core.trans.TransPort;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.UUID;

/**
 * JDK动态代理类，用于创建远程服务的代理实例
 * 该类实现了InvocationHandler接口，用于处理代理实例的方法调用
 */
@Slf4j
public class JDKProxy implements InvocationHandler {
    // 目标接口，即被代理的接口
    private Class targetInterface;
    // 传输层，用于直接调用方法
    private TransPort transPort;
    // 集群管理，用于在集群环境中调用方法
    private Cluster cluster;
    // Nacos消费者，用于获取服务实例信息
    private NacosConsumer nacosConsumer;
    // 负载均衡器，默认使用轮询策略
    private LoadBalancer loadBalancer;

    /**
     * 构造函数，用于创建JDKProxy实例
     *
     * @param targetInterface 被代理的接口
     * @param transPort       传输层实例，用于方法调用
     */
    public JDKProxy(Class targetInterface, TransPort transPort) {
        this.targetInterface = targetInterface;
        this.transPort = transPort;
    }

    /**
     * 构造函数，用于在集群环境中创建JDKProxy实例
     *
     * @param targetInterface 被代理的接口
     * @param cluster         集群管理实例，用于在集群中调用方法
     * @param nacosConsumer   Nacos消费者实例，用于获取服务实例信息
     */
    public JDKProxy(Class targetInterface, Cluster cluster, NacosConsumer nacosConsumer) {
        this.targetInterface = targetInterface;
        this.cluster = cluster;
        this.nacosConsumer = nacosConsumer;
    }

    public JDKProxy(Class targetInterface, Cluster cluster, NacosConsumer nacosConsumer, LoadBalancer loadBalancer) {
        this.targetInterface = targetInterface;
        this.cluster = cluster;
        this.nacosConsumer = nacosConsumer;
        this.loadBalancer = loadBalancer;

    }

    /**
     * 创建代理实例
     *
     * @return 代理实例
     */
    public Object createProxy() {
        return Proxy.newProxyInstance(targetInterface.getClassLoader(), new Class[]{targetInterface}, this);
    }

    /**
     * 处理代理实例的方法调用
     *
     * @param proxy  代理实例
     * @param method 被调用的方法
     * @param args   方法参数
     * @return 方法调用结果
     * @throws Throwable 方法调用过程中抛出的异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        {
            MethodInvokData methodInvokData = new MethodInvokData(null, targetInterface, method.getName(), method.getParameterTypes(), args);
            Object respValue = null;

            if (transPort != null) {
                // 同步路径 (假设 invoker 是同步的)
                respValue = transPort.invoker(methodInvokData);
            }

            if (cluster != null) {
                List<HostAndPort> hostAndPortList = nacosConsumer.getAllInstanceIpAndPort();
                String selectAddr = loadBalancer.select(hostAndPortList);
                log.info("远程服务的IP:端口:{}", selectAddr);
                ClusterFault clusterFault = parseMethodFault(method, cluster);
                if (clusterFault != null) {
                    respValue = clusterFault.invoker(selectAddr, methodInvokData, method);
                } else {
                    // ClusterClient.invoke 现在会正确返回同步结果或实际的 CompletableFuture
                    respValue = cluster.invoke(selectAddr, methodInvokData, method);
                }

            }
            return respValue;
        }

    }

    /**
     * 生成唯一标识符
     *
     * @return 唯一标识符字符串
     */
    private String generateId() {
        return UUID.randomUUID().toString();
    }

    /**
     * 解析方法上的故障注解，返回相应的故障处理对象
     *
     * @param method  被解析的方法
     * @param cluster 集群管理实例
     * @return 故障处理对象，如果没有相应的故障注解，则返回null
     */
    private ClusterFault parseMethodFault(Method method, Cluster cluster) {
        ClusterFault clusterFault = null;
        // 获取方法上的所有注解
        Annotation[] annotations = method.getAnnotations();
        for (Annotation annotation : annotations) {
            // 如果方法上有FaultRetry注解，则创建FallRetry实例
            if (annotation instanceof FaultRetry) {
                clusterFault = new FallRetry(cluster, 1);
            }
        }
        return clusterFault;
    }
}
